#![allow(non_snake_case)]
use leptos::{prelude::*, task::spawn_local};
use server_fn::codec::{MultipartData, MultipartFormData};
use shq_web_controls::{Upload, UploadDragger};
use thaw_utils::ArcOneCallback;
use web_sys::FileList;
#[component]
pub fn UploadFile(
    #[prop(into)] accept: Oco<'static, str>,
    #[prop(default = 10, into)] max_size: u16,
    #[prop(default = false, into)] multiple: bool,
    #[prop(optional, into)] file_progress_list: RwSignal<HashMap<String, String>>,
    #[prop(optional, into)] on_upload: Option<ArcOneCallback<Vec<u64>>>,
) -> impl IntoView {
    let max_byte_size = max_size as u64 * 1024 * 1024; // Convert to bytes
    let custom_request = move |file_list: FileList| {
        let on_upload = on_upload.clone();
        let len = file_list.length();
        for i in 0..len {
            if let Some(file) = file_list.get(i) {
                let file_name = file.name();
                let file_size = file.size() as u64;
                // 检查文件大小
                if file_size > max_byte_size {
                    file_progress_list.update(|fps| {
                        fps.insert(file_name, format!("文件过大，最大支持{}MB", max_size));
                    });
                    continue;
                }
                // 更新状态为"上传中"
                file_progress_list.update(|fps| {
                    fps.insert(file_name.clone(), "上传中...".to_string());
                });
                let form_data = web_sys::FormData::new().unwrap();
                form_data.append_with_blob("file", &file).unwrap();
                let on_upload = on_upload.clone();
                spawn_local(async move {
                    let res = upload_file_to_db(form_data.into()).await;
                    match res {
                        Ok(file_ids) => {
                            if let Some(on_upload) = &on_upload {
                                (on_upload)(file_ids);
                            }
                            file_progress_list.update(|fps| {
                                fps.insert(file_name, "上传成功".to_string());
                            });
                        }
                        Err(e) => {
                            file_progress_list.update(|fps| {
                                fps.insert(file_name, format!("上传失败: {}", e));
                            });
                        }
                    }
                });
            }
        }
    };
    let msg_view= move |msg: String| {
        let is_ok = msg.contains("成功");
        let idx=msg.find('@');
        if let Some(idx) = idx {
            let err_msg = &msg[idx+1..];
            let msgs= err_msg.split('|').collect::<Vec<_>>();
            view! {
                <ul tabindex="0" class="bg-base-100 rounded-box p-2 shadow">
                    {
                        msgs.iter().map(|m| {
                            view! {
                                <li class="text-red-500">{m.to_string()}</li>
                            }
                        }).collect::<Vec<_>>()
                    }
                </ul>
            }.into_any()
        } else {
            view! {
                <div class={if is_ok {"text-green-500"} else {"text-red-500"}}>
                    {msg}
                </div>
            }.into_any()
        }
    };
    view! {
        <Upload accept=accept.to_string() custom_request multiple>
            <UploadDragger>
                <div>
                    "点击或拖拽Excel文件到此处上传"
                    <div class="text-xs text-gray-500">
                        "支持的文件格式：.xlsx, .xls，最大文件大小：" {max_size} "MB"
                    </div>
                </div>
            </UploadDragger>
            <div class="mt-2 overflow-y-auto max-h-60">
                <For
                    each=move || file_progress_list.get()
                    key=|(file_name, msg)|(file_name.clone(),msg.clone())
                    let:item
                >
                    <div class="flew text-sm space-x-2">
                        <div class="flex-1">{item.0}</div>
                        <div class="flex-1">{msg_view(item.1)}</div>
                    </div>
                </For>
            </div>
        </Upload>
    }
}

use std::collections::HashMap;

#[server(
    input = MultipartFormData,
)]
async fn upload_file_to_db(data: MultipartData) -> Result<Vec<u64>, ServerFnError> {
    let mut data = data.into_inner().unwrap();
    let mut file_ids: Vec<u64> = Vec::new();
    while let Ok(Some(mut field)) = data.next_field().await {
        let name = field
            .file_name()
            .ok_or(ServerFnError::new("文件名没有找到"))?
            .to_owned();
        let mut datas: Vec<u8> = Vec::new();
        while let Ok(Some(chunk)) = field.chunk().await {
            let chunk_data: Vec<u8> = chunk.into();
            datas.extend(chunk_data);
        }
        let file_id = shq_common::prelude::store_binary(&name, datas)
            .await
            .or_else(|e| Err(ServerFnError::new(format!("存储文件到数据库失败: {}", e))))?;
        file_ids.push(file_id);
    }
    Ok(file_ids)
}
